/* 
 * Quechua - the lightweight data mining framework
 *
 * Copyright (C) 2012 Marek Denis <quechua@octogan.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef WORKFLOW_H
#define	WORKFLOW_H
#include <map>
#include <list>
#include <string>
#include <cassert>

#include "python-interface.h"
#include "debug-utils.h"

class Workflow;

class functions_s;

class DataPack;
class Channel;
class Processor;
class Algorithm;
class Logger;

class Modules;


#include "types.h"

typedef Workflow* workflow_t; // we may use shared_ptr here ot sth else.
typedef std::map<string_t,workflow_t> workflows_map;

typedef std::list<workflow_t> workflows_list;
typedef std::list<const workflow_t> const_workflows_list;
typedef workflows_list::iterator workflows_list_it;

// step for 
enum STEP {
    IDLE = 0,
    PREPROCESSING,
    PREPROCESSED,
    ALGRUNNING,
    ALGDONE,
    POSTPROCESSING,
    POSTPROCESSED,
    LOGGING,
    LOGGED,
    DONE,
    STOPPED
};
// I don't like such hacks, but...
#include "interface.h"

struct functions_s {
    Channel *channel;
    Processor *processor;
    Algorithm *algorithm;
    Logger* logger;
};

class Workflow {
       
 enum WORKFLOW_TYPE {
    SCHEDULED =0,
    TRIGGERED,
    ONESHOT
 };
 public:
     Workflow(const string_t& name_, ev::default_loop *loop);
     ~Workflow();
     
     void init(ev::default_loop *loop);
    
     void prepare() {};
     void stop(); 
     void start(); 

     STEP current_step() const { return step; };
     
     const string_t& getname() const;
 
     void init_internals(const setting_t& flow_config);
     bool add_channel(Channel* channel);
     bool add_logger(Logger* logger);
     void rem_channel();
     void rem_logger();
     
     void notify(datapack_ptr ptr,STEP step);
    
     void cyclic_reset();
     
     static STEP get_next_step(STEP step);

 private:
     const string_t name;
     STEP step;
     WORKFLOW_TYPE type;
     
     functions_s functions;

     queue_t input_queue; // channel -> workflow (used by preprocessor)
     queue_t alg_queue;   // preprocessor -> alg (used by algorithm)
     queue_t postproc_queue; // alg -> postprocessor (used by potprocessor)
     queue_t logger_queue; // postprocessor -> logger (used by logger)

     ev::periodic periodic_watcher; //used when mode = scheduled
     ev::async async_watcher; // waits for 'signal' from channel, calls iterate()
     ev::periodic iterate_watcher; // calls iterate() just to make sure nothing is stuck.

     STEP next_step();

     inline void iterate(); //main workflow loop

     void setup_scheduler(const setting_t& flow_config);
     void setup_type(const setting_t& flow_config);
     /* callbacks */
     void iterate_cb(ev::async &watcher, int revents);
     void schedule_cb(ev::periodic &watcher, int revents);
     void schedule_iterate_cb(ev::periodic &watcher, int revents);

     int  calculate_scheduled_period(const string_t& time);
     void check_working_type();
};

typedef datapack_ptr     (*thread_func_ptr)(datapack_ptr,void* object, STEP step);

void clear_queue_t(queue_t& q);

#endif	/* WORKFLOW_H */

